package edu.cicese.alz.reports;

import edu.cicese.alz.DataUtil;
import edu.cicese.alz.FrameNFCTags;
import edu.cicese.alz.FrameReport;
import edu.cicese.alz.TimeUtil;
import edu.cicese.alz.swing.CustomButton;
import edu.cicese.alz.swing.CustomComboBoxRenderer;
import edu.cicese.alz.swing.DynamicCardLayout;
import edu.cicese.alz.swing.JColorButton;
import edu.cicese.alz.swing.SwingUtil;
import edu.cicese.alz.swing.calendar.DateChooser;
import edu.cicese.alz.swing.calendar.TextFieldDateEditor;
import edu.cicese.alz.util.PropertyUtil;

import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSpinner;
import javax.swing.JToggleButton;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TreeSet;

/**
 * Created by: Eduardo Quintana Contreras
 * Date: 23/07/12
 * Time: 06:23 PM
 */
public class NFCPane extends ReportPane {

	private JToggleButton btnTypeBlock, btnTypeBar;
	private Box boxNFC;

	private TextFieldDateEditor txtBarDay;
	private DateChooser dBarDay;
	private JSpinner sIntervalFrom, sIntervalTo;

	private JRadioButton rbtBlockAll, rbtBlockFrom;
	private DateChooser dBlockFrom, dBlockTo;
	private TextFieldDateEditor txtBlockFrom, txtBlockTo;

	protected JColorButton btnColorNoData;

	protected List<NFCProfile> nfcProfiles = new ArrayList<>();
	private JComboBox cmbProfiles;
	private JPanel pColors;

	private BlockNFCPreview pNFCPreview;

	private FrameNFCTags frameNFCTags;

	public NFCPane(FrameNFCTags frameNFCTags) {
		initComponents();
		initOptionScrollPane(boxNFC);
		loadOptions();
		loadNFCProfiles();

		this.frameNFCTags = frameNFCTags;
	}

	private void initComponents() {
		// Type
		//TODO Change icons
		btnTypeBlock = SwingUtil.createToggleButton("", "Block", getIcon("acc_block"));
		btnTypeBar = SwingUtil.createToggleButton("", "Magnitude", getIcon("acc_magnitude"));

		Box boxTypes = createHorizontalBox(new Component[]{
				Box.createHorizontalGlue(),
				btnTypeBlock,
				Box.createHorizontalStrut(5),
				btnTypeBar,
				Box.createHorizontalGlue()
		});

		Box boxTypeContent = createVerticalBox(new Component[]{
				boxTypes
		});


		// Users
		Box boxUsersContent = createUsersBox();


		// Period
		txtBarDay = new TextFieldDateEditor();
		txtBarDay.setDocument(FrameReport.txtDayFromModel);
		dBarDay = new DateChooser(new Date(), "dd-MM-yyyy", txtBarDay);

		Box boxBarPeriod = createHorizontalBox(new Component[]{
				new JLabel("Day:"),
				Box.createHorizontalStrut(5),
				dBarDay
		});

		rbtBlockAll = SwingUtil.createRadioButton("All");
		rbtBlockAll.setModel(FrameReport.rbtPeriodAllModel);
		rbtBlockFrom = SwingUtil.createRadioButton("From:");
		rbtBlockFrom.setModel(FrameReport.rbtPeriodFromModel);
		ButtonGroup rgBlock = new ButtonGroup();
		rgBlock.add(rbtBlockAll);
		rgBlock.add(rbtBlockFrom);

		txtBlockFrom = new TextFieldDateEditor();
		txtBlockFrom.setDocument(FrameReport.txtDayFromModel);

		txtBlockTo = new TextFieldDateEditor();
		txtBlockTo.setDocument(FrameReport.txtDayToModel);

		txtBlockFrom.getDocument().addDocumentListener(new DateDocumentListener(txtBlockFrom, txtBlockTo));
		dBlockFrom = new DateChooser(new Date(), "dd-MM-yyyy", txtBlockFrom);

		txtBlockTo.getDocument().addDocumentListener(new DateDocumentListener(txtBlockFrom, txtBlockTo));
		dBlockTo = new DateChooser(new Date(), "dd-MM-yyyy", txtBlockTo);

		Box boxBlockDays = createHorizontalBox(new Component[]{
				rbtBlockFrom,
				Box.createHorizontalStrut(5),
				dBlockFrom,
				Box.createHorizontalStrut(3),
				new JLabel("to:"),
				Box.createHorizontalStrut(5),
				dBlockTo
		});

		Box boxBlockPeriod = createVerticalBox(new Component[]{
				rbtBlockAll,
				boxBlockDays
		}, 0);

		final JPanel pPeriodContent = createCardPane(new DynamicCardLayout());
		pPeriodContent.add("block", boxBlockPeriod);
		pPeriodContent.add("bar", boxBarPeriod);

		sIntervalFrom = SwingUtil.createSpinner(new Date(), FrameReport.sHourFromModel);
		sIntervalTo = SwingUtil.createSpinner(new Date(), FrameReport.sHourToModel);

		Box boxInterval = createHorizontalBox(new Component[]{
				new JLabel("From:"),
				Box.createHorizontalStrut(5),
				sIntervalFrom,
				Box.createHorizontalStrut(5),
				new JLabel("to:"),
				Box.createHorizontalStrut(5),
				sIntervalTo
		});

		Box boxPeriod1 = createVerticalBox(new Component[]{
				pPeriodContent
		});

		Box boxPeriod2 = createVerticalBox(new Component[]{
				boxInterval
		});

		JPanel pPeriod = createContentPane(new Box[]{
				boxPeriod1,
				boxPeriod2
		});


		// Saving options
		Box boxSavingContent = createSavingBox();


		// Advanced
		btnColorNoData = SwingUtil.createColorButton(20, 20);
		btnColorNoData.addPropertyChangeListener(new BlockColorChangeListener());

		cmbProfiles = SwingUtil.createComboBox(new String[]{}, 125, 20);
//		cmbProfiles.setModel(new CustomComboBoxModel(nfcProfiles));
		cmbProfiles.setRenderer(new CustomComboBoxRenderer());
		cmbProfiles.addActionListener(new ProfileActionListener());

		CustomButton btnNFCTags = SwingUtil.createCustomButton("", "Edit NFC profiles", getIcon("b_nfc_tag"), Color.WHITE);
		btnNFCTags.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionNFCTags();
			}
		});
		CustomButton btnAll = SwingUtil.createCustomButton("", "Select all", getIcon("b_select_all"), Color.WHITE);
		btnAll.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionSelectTags(true);
			}
		});
		CustomButton btnNone = SwingUtil.createCustomButton("", "Select none", getIcon("b_select_none"), Color.WHITE);
		btnNone.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionSelectTags(false);
			}
		});

		Box boxProfile = createHorizontalBox(new Component[]{
				new JLabel("Profile:"),
				Box.createHorizontalStrut(3),
				cmbProfiles,
				Box.createHorizontalStrut(3),
				btnNFCTags,
				Box.createHorizontalStrut(3),
				btnAll,
				Box.createHorizontalStrut(3),
				btnNone
		});

		pColors = createEmptyPane();
		pColors.setAlignmentX(Component.LEFT_ALIGNMENT);

		pNFCPreview = new BlockNFCPreview();
		CustomButton btnReloadPreview = SwingUtil.createCustomButton("", "Reload preview", getIcon("b_refresh"), Color.WHITE);
		btnReloadPreview.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionReloadPreview();
			}
		});

		Box boxPreview1 = createVerticalBox(new Component[]{
				pNFCPreview
		}, 0);

		Box boxPreview2 = createVerticalBox(new Component[]{
				btnReloadPreview
		}, 3);

		JPanel pPreview = createContentPane(new Box[]{
				boxPreview1, boxPreview2
		});

		Box boxAdvanced = createVerticalBox(new Component[]{
				boxProfile,
				Box.createVerticalStrut(5),
				createHorizontalColorBox(btnColorNoData, "No Data"),
				Box.createVerticalStrut(5),
				pColors,
				Box.createVerticalStrut(5),
				pPreview
		});


		boxNFC = Box.createVerticalBox();

		boxNFC.add(createTitlePane("Chart type"));
		boxNFC.add(Box.createVerticalStrut(7));
		boxNFC.add(boxTypeContent);
		boxNFC.add(Box.createVerticalStrut(7));

		boxNFC.add(createTitlePane("User(s)"));
		boxNFC.add(Box.createVerticalStrut(4));
		boxNFC.add(boxUsersContent);
		boxNFC.add(Box.createVerticalStrut(4));

		boxNFC.add(createTitlePane("Period"));
		boxNFC.add(Box.createVerticalStrut(4));
		boxNFC.add(pPeriod);
		boxNFC.add(Box.createVerticalStrut(4));

		boxNFC.add(createTitlePane("Saving options"));
		boxNFC.add(Box.createVerticalStrut(4));
		boxNFC.add(boxSavingContent);
		boxNFC.add(Box.createVerticalStrut(4));

		boxNFC.add(createTitlePane("Advanced options"));
		boxNFC.add(Box.createVerticalStrut(7));
		boxNFC.add(boxAdvanced);
		boxNFC.add(Box.createVerticalStrut(6));


		ButtonGroup btnGroup = new ButtonGroup();
		btnGroup.add(btnTypeBlock);
		btnGroup.add(btnTypeBar);

		btnTypeBlock.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				CardLayout cardLayoutPeriod = (CardLayout) pPeriodContent.getLayout();
				if (btnTypeBlock.isSelected()) {
					cardLayoutPeriod.show(pPeriodContent, "block");
					btnTypeBar.setBorder(new EmptyBorder(3, 3, 3, 3));
				} else {
					cardLayoutPeriod.show(pPeriodContent, "bar");
					btnTypeBar.setBorder(new LineBorder(SwingUtil.cRolloverBorder, 3));
				}
			}
		});

		btnTypeBar.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				CardLayout cardLayoutPeriod = (CardLayout) pPeriodContent.getLayout();
				if (btnTypeBar.isSelected()) {
					cardLayoutPeriod.show(pPeriodContent, "bar");
					btnTypeBlock.setBorder(new EmptyBorder(3, 3, 3, 3));
				} else {
					cardLayoutPeriod.show(pPeriodContent, "block");
					btnTypeBlock.setBorder(new LineBorder(SwingUtil.cRolloverBorder, 3));
				}
			}
		});
	}


	public void loadOptions() {
		boolean error = false;

		// Type
		if (PropertyUtil.getProperty(PropertyUtil.REP_NFC_TYPE).equals("block")) {
			btnTypeBlock.setSelected(true);
		}
		btnTypeBar.setSelected(!btnTypeBlock.isSelected());

		// Users
		try {
			rbtUsersAll.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_USERS_ALL));
			txtUsers.setText(PropertyUtil.getProperty(PropertyUtil.REP_USERS));
		} catch (Exception e) {
			e.printStackTrace();
			error = true;
		}
		rbtUsers.setSelected(!rbtUsersAll.isSelected());

		// Period
		try {
			rbtBlockAll.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_PERIOD_ALL));
		} catch (Exception e) {
			e.printStackTrace();
			error = true;
		}
		rbtBlockFrom.setSelected(!rbtBlockAll.isSelected());

		try {
			dBlockFrom.setDate(PropertyUtil.getDate(PropertyUtil.REP_PERIOD_FROM));
			dBlockTo.setDate(PropertyUtil.getDate(PropertyUtil.REP_PERIOD_TO));
		} catch (Exception e) {
			e.printStackTrace();
			error = true;
		}

		try {
			sIntervalFrom.setValue(TimeUtil.getDate(PropertyUtil.getProperty(PropertyUtil.REP_INTERVAL_FROM)));
			sIntervalTo.setValue(TimeUtil.getDate(PropertyUtil.getProperty(PropertyUtil.REP_INTERVAL_TO)));
		} catch (Exception e) {
			e.printStackTrace();
			error = true;
		}

		// Saving options
		try {
			chbSaveCharts.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_SAVE_CHARTS));
			chbShowCharts.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_SHOW_CHARTS));
		} catch (Exception e) {
			e.printStackTrace();
			error = true;
		}

		// Advanced options
		try {
			btnColorNoData.setBackground(PropertyUtil.getColor(PropertyUtil.REP_NFC_COLOR_NO_DATA));
		} catch (Exception e) {
			e.printStackTrace();
			error = true;
		}

		if (error) {
			System.out.println("An error occurred loading saved options.");
			loadDefaultOptions();
		}
	}

	public void saveOptions() {
		// Type
		PropertyUtil.setProperty(PropertyUtil.REP_NFC_TYPE, btnTypeBlock.isSelected() ? "block" : "bar");

		// Users
		PropertyUtil.setProperty(PropertyUtil.REP_USERS_ALL, String.valueOf(rbtUsersAll.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_USERS, txtUsers.getText());

		// Period
		PropertyUtil.setProperty(PropertyUtil.REP_PERIOD_ALL, String.valueOf(rbtBlockAll.isSelected()));
		if (!txtBlockFrom.hasDateError() || !txtBlockFrom.hasFormatError()) {
			PropertyUtil.setProperty(PropertyUtil.REP_PERIOD_FROM, SwingUtil.calendarDateFormat.format(dBlockFrom.getDate()));
		}
		if (!txtBlockTo.hasDateError() || !txtBlockTo.hasFormatError()) {
			PropertyUtil.setProperty(PropertyUtil.REP_PERIOD_TO, SwingUtil.calendarDateFormat.format(dBlockTo.getDate()));
		}
		PropertyUtil.setProperty(PropertyUtil.REP_INTERVAL_FROM, SwingUtil.timeFormat.format(sIntervalFrom.getValue()));
		PropertyUtil.setProperty(PropertyUtil.REP_INTERVAL_TO, SwingUtil.timeFormat.format(sIntervalTo.getValue()));

		// Saving options
		PropertyUtil.setProperty(PropertyUtil.REP_SHOW_CHARTS, String.valueOf(chbShowCharts.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_SAVE_CHARTS, String.valueOf(chbSaveCharts.isSelected()));

		// Advanced options
		//TODO
	}

	public void loadDefaultOptions() {
		PropertyUtil.setDefaultNFCProperties();
		loadOptions();
	}

	public void generate() {
		try {
			sIntervalFrom.commitEdit();
			sIntervalTo.commitEdit();
		} catch (ParseException e) { /*ignored*/ }

		//TODO Check errors

		TreeSet<Integer> userIDs = null;
		if (!rbtUsersAll.isSelected()) {
			if (!txtUsers.hasError()) {
				userIDs = getUsers(txtUsers);
			} else {
				//show dialog with error
			}
		} else {
			// get all the subjects in the DB
			userIDs = getUsers();
		}
		if (btnTypeBlock.isSelected()) {

			for (int userID = 1; userID <= 15; userID++) {
				userIDs.clear();
				userIDs.add(userID);
				Date begin = TimeUtil.getDate(DataUtil.dates[userID - 1][0], TimeUtil.sdfDateOnly);
				Date end = TimeUtil.getDate(DataUtil.dates[userID - 1][1], TimeUtil.sdfDateOnly);
				NFCReport nfcReport = new NFCReport(
						userIDs,
						begin,
						end,
						(Date) sIntervalFrom.getValue(),
						(Date) sIntervalTo.getValue(),
						chbShowCharts.isSelected(),
						chbSaveCharts.isSelected(),
						getProfileTags(),
						btnColorNoData.getBackground()
				);

				nfcReport.createCharts();
			}

			//TODO Uncomment
//			NFCReport nfcReport = new NFCReport(
//					userIDs,
//					dBlockFrom.getDate(),
//					dBlockTo.getDate(),
//					(Date) sIntervalFrom.getValue(),
//					(Date) sIntervalTo.getValue(),
//					chbShowCharts.isSelected(),
//					chbSaveCharts.isSelected(),
//					getProfileTags(),
//					btnColorNoData.getBackground()
//			);
//
//			nfcReport.createCharts();
		}
	}


	private void loadNFCProfiles() {
		nfcProfiles.clear();
		cmbProfiles.removeAllItems();

		String profileString = PropertyUtil.getProperty(PropertyUtil.NFC_PROFILES);
		if (!profileString.equals("")) {
			String[] profiles = profileString.split(";");
			for (String profileName : profiles) {
				NFCProfile nfcProfile = new NFCProfile(profileName, profileName, false);
//				((CustomComboBoxModel) cmbProfiles.getModel()).addElement(nfcProfile);
				cmbProfiles.addItem(nfcProfile);

				loadProfileTags(nfcProfile);
			}
			cmbProfiles.setSelectedIndex(0);
		}
	}

	private void loadProfileTags(NFCProfile nfcProfile) {
		String profileProperty = PropertyUtil.getProperty("NFC_PROFILE_" + nfcProfile.getProfileName());
		ArrayList<NFCTag> nfcTags = nfcProfile.getTags();

		if (!profileProperty.equals("")) {
			try {
				String[] colors = profileProperty.split(";");

				if (colors.length > 0) {
					for (String color : colors) {
						String[] values = color.split(",");

						JColorButton button = SwingUtil.createColorButton(20, 20, new Color(Integer.valueOf(values[1])));
						button.addPropertyChangeListener(new BlockColorChangeListener());

						JCheckBox checkBox = SwingUtil.createCheckBox(values[0], 150, 20);
						checkBox.setSelected(true);
						checkBox.addActionListener(new SelectionChangeListener());
						
						nfcTags.add(new NFCTag(checkBox, button));
					}
				}
			} catch (NullPointerException ex) {
				ex.printStackTrace();
				nfcTags.clear();
			}
		}
	}

	private void showProfileTags() {
		if (getProfileTags().size() > 0) {
			addProfileTagsToPane();
		} else {
			empty(pColors);
		}

		revalidate();
		repaint();
	}

	private void addProfileTagsToPane() {
		List<NFCTag> profileTags = getProfileTags();
		int tagRowSize = 8;
		Box[] boxes = new Box[(int) Math.ceil((double) profileTags.size() / tagRowSize)];

		for (int b = 0, c = 0; b < boxes.length; b++) {
			boxes[b] = Box.createVerticalBox();
			if (b != 0) {
				setBoxLeftBorder(boxes[b], 20);
			}

			for (int i = c; i < c + tagRowSize && i < profileTags.size(); i++) {
				Box boxTag = createHorizontalBox(new Component[]{
						profileTags.get(i).getProfileCheckBox(),
						Box.createHorizontalStrut(3),
						profileTags.get(i).getTagButton(),
				});
				boxes[b].add(boxTag);
				boxes[b].add(Box.createVerticalStrut(2));
			}
			c += tagRowSize;
		}

		pColors.removeAll();
		setPaneContent(pColors, boxes);

		int width, height;

		// set tags' panel width
		// JCheckBox's width = 100
		// extra = 3
		// JColorButton's width = 20
		width = boxes.length * 173 + (boxes.length - 1) * 20;

		// set tags' panel height
		if (profileTags.size() >= tagRowSize) {
			height = tagRowSize * 22;
		} else {
			height = profileTags.size() * 22;
		}
		pColors.setPreferredSize(new Dimension(width, height));
		pColors.setMinimumSize(pColors.getPreferredSize());
		pColors.setMaximumSize(pColors.getPreferredSize());
	}

	protected List<NFCTag> getProfileTags() {
		if (cmbProfiles.getItemCount() > 0 && cmbProfiles.getSelectedItem() != null) {
			return getSelectedProfile().getTags();
		} else {
			return new ArrayList<>();
		}
	}

	private NFCProfile getSelectedProfile() {
		return (NFCProfile) cmbProfiles.getSelectedItem();
	}


	private void actionNFCTags() {
		if (frameNFCTags == null) {
			frameNFCTags = new FrameNFCTags();
		}
		frameNFCTags.setNFCPane(this);
		frameNFCTags.setModal(true);
		frameNFCTags.setVisible(true);
	}

	private void actionSelectTags(boolean select) {
		for (NFCTag nfcTag : getProfileTags()) {
			nfcTag.getProfileCheckBox().setSelected(select);
		}
		pNFCPreview.repaint();
	}

	private void actionReloadPreview() {
		repaintBlockPreview();
	}


	public void reloadProfiles() {
		loadNFCProfiles();
		showProfileTags();
		frameNFCTags.setModal(false);
	}

	protected void repaintBlockPreview() {
		pNFCPreview.setNFCValues(btnColorNoData.getBackground(), getProfileTags());
		pNFCPreview.repaint();
	}


	class ProfileActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			if (cmbProfiles.getSelectedIndex() != -1) {
				repaintBlockPreview();
			}
			showProfileTags();
		}
	}

	class SelectionChangeListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			pNFCPreview.repaint();
		}
	}

	class BlockColorChangeListener implements PropertyChangeListener {
		@Override
		public void propertyChange(PropertyChangeEvent evt) {
			if (evt.getPropertyName().equals("background")) {
				pNFCPreview.updateNFCValues(btnColorNoData.getBackground());
				pNFCPreview.repaint();
			}
		}
	}
}
